#ifndef __DATASPACE_HH__
#define __DATASPACE_HH__

#include <dataspace/axes.h>
#include <dataspace/datafield.h>

class DataSpace
{
public:
  DataSpace();

  void set_data_field(DataField*);

  template <typename V>
    void set_value(AxesCoor& coor, const V& value, bool axes_mod_f) {
    if (get_dyntype<V>() != data_field->get_value_dyntype()) {
      throw Error(__FILE__, __LINE__, "DataSpace::set_value: value and datafield dyntype mismatch");
    }
    DynObject dd(get_dyntype<V>(), membuf_t((char*)&value, sizeof(value)));
    this->set_value__(coor, dd, axes_mod_f);
  }
 
  void set_value__(const AxesCoor& coor, const DynObject& dd, bool axes_mod_f); 
  bool is_none_at_coor(const AxesCoor& coor) const;

  void create_datafield(const string& ds_fn, 
			DynType* dt, const vector<data_index_t>& max_shape);
  bool load(const string& ds_fn, bool writable);
  void save();

  void dump() const;
  void print(ostream& out) const;

  bool onedim_range(vector<pair<axis_index_t, axis_index_t> >& range_axis_indexes,
		    vector<AxesCoor>* tics,
		    vector<DynObject>* values) const;

  Axes axes;
  DataField* get_data_field() { return data_field; }
  const DataField* get_data_field() const { return data_field; }

private: 
  string datafield_fn;
  DataField* data_field;
};

class DataSpaceRange;
class DataSpaceRangeTraverseCB : public NDimRangeTraverseCB
{
public:
  DataSpaceRange* dataspace_range;
  DataSpaceRangeTraverseCB();
  virtual void do_it(const vector<size_t>& axis_indexes_coor) = 0;
};

class DataSpaceRange
{
public:
  DataSpace* dataspace;
  AxesRange axes_range;
  DataSpaceRange(DataSpace*);

  void set_left(const string& dim, const DynObject& l);
  void set_right(const string& dim, const DynObject& r);
  void set_left_right(const string& dim, 
		      const DynObject& l,
		      const DynObject& r);
  void set_left_right(const string& dim, const DynObject& lr);

  void get_values(vector<DynObject>*, vector<AxesCoor>*) const;

  void traverse(DataSpaceRangeTraverseCB*);
};

#endif
